package repository

import (
	"errors"
	"gitee.com/fierce_wolf/go-fox-edge-common/commEntity"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/MD5"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Map"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Method"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Number"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Sort"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/String"
	"gitee.com/fierce_wolf/go-fox-edge-common/edgeEntity"
	"sync"
)

type repoCloudIotTemplateInstallStatus struct {
	mutex     sync.Mutex
	statusMap map[string]interface{}
}

func (e *repoCloudIotTemplateInstallStatus) mapSetValue(keys ...interface{}) {
	e.mutex.Lock()
	defer e.mutex.Unlock()
	Map.SetValue(e.statusMap, keys...)
}

func (e *repoCloudIotTemplateInstallStatus) mapGetValue(keys ...interface{}) (interface{}, error) {
	e.mutex.Lock()
	defer e.mutex.Unlock()
	return Map.GetValue(e.statusMap, keys...)
}

func (e *repoCloudIotTemplateInstallStatus) Extend(mapList []interface{}) {
	for _, data := range mapList {
		comp := data.(map[string]interface{})

		iotName := Map.GetString(comp, "iotName", "")
		subsetName := Map.GetString(comp, "subsetName", "")
		if Method.HasEmpty(iotName, subsetName) {
			continue
		}

		// 云端的最新版本信息
		lastVersion := Map.GetMap(comp, "lastVersion", nil)
		if lastVersion == nil {
			continue
		}

		cloudId := Map.GetString(lastVersion, "id", "")
		cloudMd5 := Map.GetString(lastVersion, "md5", "")
		if Method.HasEmpty(cloudId, cloudMd5) {
			continue
		}

		// 扫描本地状态：计算并保存
		e.scanStatus(iotName, subsetName, cloudId, cloudMd5)

		// 取出本地状态
		val, err := e.mapGetValue(iotName, subsetName, "status")
		if err != nil {
			continue
		}

		status := Number.MakeInt(val)
		lastVersion["status"] = status
	}
}

func (e *repoCloudIotTemplateInstallStatus) scanStatus(iotName, subsetName, cloudId, cloudMd5 string) error {
	// 简单验证
	if Method.HasEmpty(iotName, subsetName) {
		return errors.New("参数不能为空: iotName, subsetName")
	}

	// 阶段1：未下载
	status := RepoStatusConstant.NotDownloaded

	// 场景1：本地没有组件信息
	repoCompEntity := LocalIotTemplate.getCompEntity(iotName, subsetName)
	if repoCompEntity == nil {
		e.mapSetValue(iotName, subsetName, "status", status)
		return nil
	}

	// 场景2：本地没有来自云端的安装信息
	installVersion := Map.GetMap(repoCompEntity.CompParam, "installVersion", nil)
	if installVersion == nil {
		e.mapSetValue(iotName, subsetName, "status", status)
		return nil
	}

	// 场景3：本地来自云端的信息，不完整
	if installVersion["id"] == nil || installVersion["updateTime"] == nil {
		e.mapSetValue(iotName, subsetName, "status", status)
		return nil
	}

	// 阶段5："已下载，已安装!"
	status = RepoStatusConstant.Installed
	e.mapSetValue(iotName, subsetName, "status", status)

	// 阶段6：检查是否待升级
	if cloudId == installVersion["id"] {
		// 算法要调整，暂时注释
		//if strings.ToLower(e.getMD5Txt(iotName, deviceType)) != strings.ToLower(cloudMd5) {
		//	status = RepoStatusConstant.DamagedPackage
		//	e.mapSetValue(iotName, deviceType, "status", status)
		//}
	}

	// 阶段7：检查是否待升级
	if cloudId != installVersion["id"] {
		status = RepoStatusConstant.NeedUpgrade
		e.mapSetValue(iotName, subsetName, "status", status)
	}

	return nil
}

func (e *repoCloudIotTemplateInstallStatus) getMD5Txt(iotName, subsetName string) string {
	entityList := LocalIotTemplate.GetIotTemplateEntityList(iotName, subsetName)
	txt := e.getOrderText(entityList)
	md5 := MD5.GetStringMD5(txt)
	return md5
}

func (e *repoCloudIotTemplateInstallStatus) getOrderText(list []commEntity.IEntity) string {
	Sort.Sort(list, func(entity1, entity2 interface{}) bool {
		dv1 := entity1.(*edgeEntity.IotTemplateEntity)
		dv2 := entity2.(*edgeEntity.IotTemplateEntity)

		name1 := dv1.TemplateType + ":" + dv1.TemplateName
		name2 := dv2.TemplateType + ":" + dv2.TemplateName
		return name1 < name2
	})

	sb := ""
	for _, entity := range list {
		sb += e.getOrderTextEntity(entity)
		sb += ";"
	}

	return sb
}

func (e *repoCloudIotTemplateInstallStatus) getOrderTextEntity(entity commEntity.IEntity) string {
	deviceModelEntity := entity.(*edgeEntity.IotTemplateEntity)

	// 注意：不要调整代码顺序，这是跟fox-cloud保持一致的算法，两边要同步修改
	values := make([]interface{}, 0)
	values = append(values, deviceModelEntity.TemplateType)
	values = append(values, deviceModelEntity.TemplateName)
	values = append(values, String.GetMapString(deviceModelEntity.TemplateParam))
	values = append(values, String.GetMapString(deviceModelEntity.ExtendParam))

	return String.GetSliceString(values)
}
